﻿#include "Framework/Application.h"
#include "Containers/String8.h"

// #include "Network/TCPServer.h"
#include "Network/UDPClient.h"
#include "Network/UDPServer.h"
#include "Network/HttpRequest.h"
#include "Network/HttpResponse.h"
#include "Network/HttpServer.h"

#include "Network/TCPServer.h"
#include "Network/TCPClient.h"

#include "Output/Console.h"

#define TCP_LISTENER_MODE 0
#define TCP_CLIENT_MODE 1
#define TCP_SERVER_AND_CLIENT_MODE 6

#define UDP_LISTENER_MODE 2
#define UDP_CLIENT_MODE 3


#define HTTP_REQUEST_MODE 4
#define HTTP_SERVER_MODE 5

#define TEST_MODE TCP_SERVER_AND_CLIENT_MODE

int main(int argc, char* argv[])
{  
   auto App=NewObject<RApplication>();
   
   SApplicationArgument Argument;
   Argument.ExecutablePath=argv[0];
   App->Initialize(Argument);

   auto IP = SIPAddress::LocalHostIPv4;
   auto Port = 3988;
// #if TEST_MODE == TCP_LISTENER_MODE
//    auto Server= CTCPServer::Create(IP,Port);
//    Server->OnClientAccepted.Bind([](TThreadSafeSharedPtr<CTCPClient> Client)
//    {
//       std::cout<<"Client Accepted"<<std::endl;

//       Client->OnDataReceived.Bind([](TVector<uint8_t> Data)
//       {
//          std::cout<<"Data Received"<<std::endl;
//          Data.Add(u8'\0');
//          CString8 String((char8_t*)Data.Data());
//          std::cout<<String.CStr()<<std::endl;
//       });

//       Client->OnDisconnected.Bind([]()
//       {
//          std::cout<<"Client Disconnected"<<std::endl;
//       });
//    }
//    );
//    Server->StartAcceptClient();
// #elif TEST_MODE == TCP_CLIENT_MODE
//    //test client

//    auto Client=CTCPClient::Create(IP,Port);//  WH::MakeThreadSafeSharedPtr<CTCPClient>(IP,Port);
//    if(!Client)
//    {
//       std::cout<<"cant connect to server"<<std::endl;
//       return -1;
//    }

//    Client->OnDataReceived.Bind([](TVector<uint8_t> Data)
//    {
//       std::cout<<"Data Received"<<std::endl;
//       Data.Add(u8'\0');
//       for(auto Byte: Data)
//       {
//          std::cout<<std::hex<<(int)Byte<<" ";//<<std::endl;
//       }
//       std::cout<<std::endl;
//    });

//    for(int i=0;i<10;i++)
//    {
//       Client->Send(CString(U"Index:") + (int64_t)i );
//    }

// #elif TEST_MODE==UDP_CLIENT_MODE
//    auto Client=WH::MakeThreadSafeSharedPtr<CUDPClient>();
//    Client->Send(CString(U"Hello World!"),IP,Port);
//    Client->Send(CString(U"Love you Forever"),IP,Port); 

// #elif TEST_MODE==UDP_LISTENER_MODE
//    auto Server= CUDPServer::Create(IP,Port);
//    assert(Server && "cant create udp server");
//    Server->OnDataReceived.Bind([](TVector<uint8_t> Data, const SIPAddress& FromIP, uint16_t FromPort)
//    {
//       std::cout<<"Data Received"<<std::endl;
//       Data.Add(u8'\0');
//       CString8 String((char8_t*)Data.Data());
//       std::cout<<String.CStr()<<std::endl;

//       std::cout<<"From IP:"<<FromIP.ToString().ToUtf8String().CStr()<<std::endl;
//       std::cout<<"From Port:"<<FromPort<<std::endl;
//    });

// #elif TEST_MODE==HTTP_REQUEST_MODE
//    //must run a http server first by: python3 SimpleHttpServer.py
   
//    auto Request=std::make_shared<CHttpRequest>();
//    Request->Url= CUrl::Create(U"localhost:5000").GetValue();
//    Request->ProcessRequest();

//    Request->OnRequestFinished.Bind([](std::shared_ptr<CHttpResponse> Response)
//    {
//       std::cout<<"Request Finished"<<std::endl;
//       WH::Cout()<<Response->Body <<WH::EndL();
//    });
// #elif TEST_MODE==HTTP_SERVER_MODE
//    auto HttpServer= std::make_shared<CHttpServer>(IP,Port);
//    HttpServer->AddRoute(U"/",[](std::shared_ptr<CHttpIncomingRequest> Request)
//    {
//       auto Response=std::make_shared<CHttpResponse>();
//       Response->HeadParameters.Add(U"Content-Type",U"text/html");
//       Response->Body=U"Hello World!";
//       return Response;
//    });
// #endif

#if TEST_MODE == TCP_LISTENER_MODE
   auto Server= CTCPServer::Create();

   TThreadSafeSharedPtr<CTCPClient> NewClient;
   TThreadSafeWeakPtr<CTCPServer> ServerWeak=Server;
   Server->OnClientConnected.Bind([&NewClient,ServerWeak]() mutable
   {
      auto Server=ServerWeak.Lock();
      std::cout<<"Client Accepted"<<std::endl;

      NewClient=Server->GetNextPendingClient();
      TThreadSafeWeakPtr<CTCPClient> ClientWeak=NewClient;
      NewClient->OnDataReceived.Bind([ClientWeak]() mutable
      {
         auto Client=ClientWeak.Lock();
         auto Data=Client->ReadAllData();
         std::cout<<"Data Received"<<std::endl;
         Data.Add(u8'\0');
         CString8 String((char8_t*)Data.Data());
         std::cout<<String.CStr()<<std::endl;

         //发一条消息回去
         Client->Send(CString(U"Hello World!"));
      });

      NewClient->OnDisconnected.Bind([]()
      {
         std::cout<<"Client Disconnected"<<std::endl;
      });
   }
   );

   Server->Listen(IP,Port);

#elif TEST_MODE == TCP_CLIENT_MODE
   auto Client=CTCPClient::Create();
   TThreadSafeWeakPtr<CTCPClient> ClientWeak=Client;

   Client->OnDataReceived.Bind([ClientWeak]() mutable
   {
      auto Client=ClientWeak.Lock();
      if(!Client)
      {
         return;
      }
      auto Data=Client->ReadAllData();
      std::cout<<"Data Received"<<std::endl;
      Data.Add(u8'\0');
      CString8 String((char8_t*)Data.Data());
      std::cout<<String.CStr()<<std::endl;

      //发一条消息回去
      Client->Send(CString(U"Hello World!"));
   });

   Client->OnDisconnected.Bind([]()
   {
      std::cout<<"Client Disconnected"<<std::endl;
   });

   Client->Connect(IP,Port);
#elif TEST_MODE==TCP_SERVER_AND_CLIENT_MODE
   auto Server= CTCPServer::Create();

   TThreadSafeSharedPtr<CTCPClient> NewClient;
   TThreadSafeWeakPtr<CTCPServer> ServerWeak=Server;
   Server->OnClientConnected.Bind([&NewClient,ServerWeak]() mutable
   {
      auto Server=ServerWeak.Lock();
      std::cout<<"Client Accepted"<<std::endl;

      NewClient=Server->GetNextPendingClient();
      TThreadSafeWeakPtr<CTCPClient> ClientWeak=NewClient;
      NewClient->OnDataReceived.Bind([ClientWeak]() mutable
      {
         auto Client=ClientWeak.Lock();
         auto Data=Client->ReadAllData();
         std::cout<<"Server Received"<<std::endl;
         Data.Add(u8'\0');
         CString8 String((char8_t*)Data.Data());
         std::cout<<String.CStr()<<std::endl;

         //发一条消息回去
         Client->Send(CString(U"Server!"));
      });

      NewClient->OnDisconnected.Bind([]()
      {
         std::cout<<"Server Disconnected"<<std::endl;
      });

      NewClient->OnErrorOccured.Bind([](ETCPClientError Error)
      {
         std::cout<<"Server Client Error!"<<std::endl;
      });
   }
   );

   Server->OnErrorOccured.Bind([](ETCPServerError Error)
   {
      std::cout<<"Server Error!"<<std::endl;
   });

   Server->Listen(IP,Port);


   auto Client=CTCPClient::Create();
   TThreadSafeWeakPtr<CTCPClient> ClientWeak=Client;

   Client->OnDataReceived.Bind([ClientWeak]() mutable
   {
      auto Client=ClientWeak.Lock();
      if(!Client)
      {
         return;
      }
      auto Data=Client->ReadAllData();
      std::cout<<"Client Received"<<std::endl;
      Data.Add(u8'\0');
      CString8 String((char8_t*)Data.Data());
      std::cout<<String.CStr()<<std::endl;

      //发一条消息回去
      Client->Send(CString(U"Client!"));
   });

   Client->OnDisconnected.Bind([]()
   {
      std::cout<<"Client Disconnected"<<std::endl;
   });

   Client->OnErrorOccured.Bind([](ETCPClientError Error)
   {
      std::cout<<"Client Error!"<<std::endl;
   });

   Client->Connect(IP,Port);

   int i=0;
   while(i<100)
   {
      i++;
      std::this_thread::sleep_for(std::chrono::milliseconds(1000));
      Client->Send(CString(U"Client Hello World!")+i);
   }
   //Client->Send(CString(U"Client Hello World!"));

#endif 

   App->Run();

}